package org.jeecg.modules.iot.mqtt.server.service.impl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
//import org.equ.common.constant.RentalCacheConstant;
//import org.equ.common.feign.IRentalEBikeAPI;
//import org.equ.common.model.entity.RentalEBike;
//import org.equ.common.model.entity.RentalEBikeType;
//import org.equ.common.model.vo.RentalEBikeQueryVo;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.base.BaseMap;
import org.jeecg.common.modules.redis.client.JeecgRedisClient;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.iot.jtt808.JTT808Decoder;
import org.jeecg.modules.iot.jtt808.req.TransparencyMsg;
import org.jeecg.modules.iot.cache.EBikeCache;
import org.jeecg.modules.iot.mqtt.entity.MqttMessageJson;
import org.jeecg.modules.iot.model.Consumption;
import org.jeecg.modules.iot.model.Location;
import org.jeecg.modules.iot.model.control.TaitModbusControllerResponse;
import org.jeecg.modules.iot.model.power.TaiPower;
import org.jeecg.modules.iot.model.power.TaitModbusPowerResponse;
import org.jeecg.modules.iot.mqtt.server.service.MqttSendCommand;
import org.jeecg.modules.iot.mqtt.server.service.processor.carOperate.CarService;
import org.jeecg.modules.iot.mqtt.server.service.processor.control.TaitModbusControlParser;
import org.jeecg.modules.iot.mqtt.server.service.processor.powerOperate.TaitModbusParser;
import org.jeecg.modules.iot.service.*;
import org.jeecg.modules.iot.utils.AddressUtil;
import org.jeecg.modules.iot.utils.JsonUtil;
import org.jeecg.modules.rental.api.IRentalEBikeAPI;
import org.jeecg.modules.rental.constant.RentalCacheConstant;
import org.jeecg.modules.rental.entity.RentalEBike;
import org.jeecg.modules.rental.entity.RentalEBikeType;
import org.jeecg.modules.websocket.constant.WsMessageConstant;
import org.jeecg.modules.websocket.enums.WsBussinesType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Component("0900")
@Slf4j
public class Command_0900_Send implements MqttSendCommand {

    /* @Autowired
     private SseEmitterManager sseEmitterManager;*/
    @Autowired
    TaitModbusParser taitModbusParser;

    private Instant lastBMSEntryTime = null; // 添加一个变量来存储上次进入 BMS 的时间

    @Autowired
    TaitModbusControlParser taitModbusControlParser;
    @Autowired
    IPowerService powerService;

    @Autowired
    EBikeCache eBikeCache;

    @Autowired
    private CarService carService;

    /*@Autowired
    private RentalEBikeMapper rentalCarMapper;

    @Autowired
    private RentalEBikeTypeMapper rentalCarTypeMapper;*/

    @Autowired
    private IRentalEBikeAPI iRentalEBikeAPI;

    private ConcurrentHashMap<String, LowBatteryAlertInfo> lowBatteryAlertInfoMap = new ConcurrentHashMap<>();
    @Autowired
    ILocationService locationService;

    @Autowired
    private IConsumptionService consumptionService;

    @Autowired
    private CacheManager cacheManager;

  /*  @Autowired
    private IRentalAccountPackageService accountPackageService;
    @Autowired
    private   IRentalPayAccountService rentalPayAccountService;*/

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private AddressUtil addressUtil;


    @Autowired
    private JeecgRedisClient jeecgRedisClient;


    private static final String NATIONAL_STANDARD_SPEED_LIMIT_KEY = "vehicle:%s:nationalStandardSpeedLimit"; //  Redis key 格式

    @Override
    public void execute(MqttMessageJson mqttMessageJson, MqttMessageJson mqttMessageJsonReturn) throws Exception {
        TransparencyMsg jt808DataPacket = (TransparencyMsg) JTT808Decoder.decode(mqttMessageJson.getData());

        //Tc msg = (T0900) JT808Utils.decode(mqttMessageJson.getData());
        pushPowerToFrontEndAsync(mqttMessageJson, jt808DataPacket);
    }

    private void pushPowerToFrontEndAsync(MqttMessageJson mqttMessageJson, TransparencyMsg jt808DataPacket) throws IOException {
        /**/
        System.out.println("进入" + mqttMessageJson.getTimestamp());
        // 首先解析从机地址
        ByteBuf buf = Unpooled.wrappedBuffer(jt808DataPacket.getTransparentMsgContent());
        int slaveAddressTrans = buf.readByte() & 0xFF;
        System.out.println("从机地址" + slaveAddressTrans);
        buf.release();
        // 根据从机地址选择解析器
        if (slaveAddressTrans == 0x03) { // BMS 地址
            Integer startAdress = addressUtil.getAddressAndDelete(mqttMessageJson.getId(), mqttMessageJson.getSeq());
            System.out.println("获取得流水号:" + startAdress);
            TaitModbusPowerResponse tai = taitModbusParser.parseBatteryData(jt808DataPacket.getTransparentMsgContent(), startAdress);
            // 记录进入 BMS 的时间并计算时间间隔
            Instant currentBMSEntryTime = Instant.now();
            if (lastBMSEntryTime != null) {
                Duration duration = Duration.between(lastBMSEntryTime, currentBMSEntryTime);
                System.out.println("BMS时间间隔: " + duration.getSeconds() + " 秒"); //  改用 getSeconds()
            }
            lastBMSEntryTime = currentBMSEntryTime;

            /*测试控制器*/
            /*LambdaQueryWrapper<RentalEBike> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(RentalEBike::getCarCode, mqttMessageJson.getId());
            List<RentalEBike> list=rentalCarMapper.selectList(queryWrapper);
            for (RentalEBike car : list) {
                car.setControlJson(tai.toString());
                rentalCarMapper.updateById(car);
            }*/
            if (tai != null) {
                //System.out.println("解析数据BMS:"+tai.toString());
                int slaveAddress = tai.getSlaveAddress();
                int functionCode = tai.getFunctionCode();
                // 根据功能码解析数据
                if (slaveAddress == 0x01) {
                    System.out.println(slaveAddress + "地址--------");
                } else if (slaveAddress == 0x03) {
                    if (functionCode == 0x03) {
                        TaiPower taiPower = new TaiPower();
                        taiPower.setVoltage(roundToTwoDecimalPlaces(tai.getBatteryPackVoltage()));
                        taiPower.setCurrent(roundToTwoDecimalPlaces(tai.getBatteryCurrent()));
                        //tai.getLowGroupCellVoltage().get
                        int highCount = 0;
                        int lowCount = 0;
                        for (float voltage : tai.getHighGroupVoltages()) {
                            if (voltage != 0) {
                                highCount++;
                            }
                        }
                        for (float voltage : tai.getLowGroupVoltages()) {
                            if (voltage != 0) {
                                lowCount++;
                            }
                        }
                        //累计耗电量


                        //Float rP=((highCount+lowCount)*2.83f+tai.getBatteryPackVoltage())/2;
                        Float rP = (float) (tai.getBatteryPackVoltage() * 0.95);
                        //System.out.println("高位："+highCount +" 低位："+lowCount+"电池电压"+tai.getBatteryPackVoltage());
                        taiPower.setRPow(roundToTwoDecimalPlaces(rP * tai.getBatteryRemainingCapacity() / 1000));
                        taiPower.setSoh(tai.getBatteryPackHealth());
                        //System.out.println(tai.getBatteryRemainingCapacity()+"--------------剩余容量----------"+taiPower.getRPow());
                        taiPower.setTs(new Timestamp(new Date().getTime()));
                        /*剩余电量*/
                        taiPower.setRPowCap(roundToTwoDecimalPlaces((float) tai.getBatteryRelativeCapacity()));
                        taiPower.setDeviceId(mqttMessageJson.getId());
                        TaiPower power = powerService.queryLastByDeviceId(mqttMessageJson.getId());
                        System.out.println(taiPower.getRPow() + "剩余电量");
                        if (taiPower.getRPow() == 0f) {
                            return;
                        }
                        handlePowerData(mqttMessageJson.getId(), taiPower.getRPowCap());

                        if (power == null) {
                            power = new TaiPower();

                        }

                        Location location = locationService.queryByDeviceId(mqttMessageJson.getId());
                        //Location staticLocation=locationService.queryStaticByDeviceId(mqttMessageJson.getId());
                        //Location moveLocation=locationService.queryMoveByDeviceId(mqttMessageJson.getId());
                        updateEPower(taiPower, power, location, tai);
                        eBikeCache.updateVehicleBatteryLevel(mqttMessageJson.getId(), Double.valueOf(taiPower.getRPowCap()));


               /* if (location != null) {
                    if (staticLocation != null && moveLocation != null) {
                        // 1. staticLocation 和 moveLocation 都非空
                        if (staticLocation.getTs().after(moveLocation.getTs())) {
                            // 1.1 staticLocation 的时间在 moveLocation 之后
                            if ((staticLocation.getTs().getTime() - moveLocation.getTs().getTime()) >= 30 * 60 * 1000) {
                                // 1.1.1 时间差大于等于 30 分钟，不做任何操作
                            } else {
                                // 1.1.2 时间差小于 30 分钟，更新 taiPower.ePower

                            }
                        } else {
                            // 1.2 staticLocation 的时间在 moveLocation 之前，更新 taiPower.ePower
                            updateEPower(taiPower, power, location, tai);
                        }
                    } else if (staticLocation != null && moveLocation == null) {
                        // 2. staticLocation 不为空，moveLocation 为空，表示一直静止，不做任何操作
                    } else {
                        // 3. 其他情况，更新 taiPower.ePower
                        updateEPower(taiPower, power, location, tai);
                    }
                }*/


                        String powerMessage = JsonUtil.createPubJson(WsBussinesType.POWER.getCode(), true, taiPower);
                        powerService.add(taiPower);
                        //sseEmitterManager.sendMessageToEmitter(mqttMessageJson.getId(), WsBussinesType.ALLINFO.getType(), powerMessage);

                        BaseMap poweParams = new BaseMap();
                        poweParams.add("terminalCode", mqttMessageJson.getId());
                        poweParams.add("message", powerMessage);
                        jeecgRedisClient.sendMessage(WsMessageConstant.EBIKE_REALTIME_MESSAGE, poweParams);

                        /*JsonNode poweParams = JacksonUtils.createEmptyJsonNode()
                                .put("terminalCode", mqttMessageJson.getId())
                                .put("message", powerMessage);
                        rabbitMqClient.sendMessage( WsMsgQueueConstant.EBIKE_REALTIME_INFO_QUEUE, poweParams);*/


                    }
                }
            }

        } else if (slaveAddressTrans == 0x04) { // 控制器地址
            Integer startAdress = addressUtil.getAddressAndDelete(mqttMessageJson.getId(), mqttMessageJson.getSeq());
            TaitModbusControllerResponse taitModbusControllerResponse = taitModbusControlParser.parseControllerData(jt808DataPacket.getTransparentMsgContent(), startAdress);
            System.out.println("获取得流水号:" + startAdress);

            if (taitModbusControllerResponse != null) {
                // ... 处理控制器数据 ...
                /*测试控制器*/
               /* LambdaQueryWrapper<RentalEBike> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(RentalEBike::getCarCode, mqttMessageJson.getId());*/

                 if (taitModbusControllerResponse.isNationalStandardSpeedLimit()) {
                    // 将 nationalStandardSpeedLimit 数据放入 Redis
                    String redisKey = String.format(NATIONAL_STANDARD_SPEED_LIMIT_KEY, mqttMessageJson.getId());
                    redisUtil.set(redisKey, taitModbusControllerResponse.isNationalStandardSpeedLimit()); //  使用 RedisUtil 存储数据
                }

                RentalEBike rentalCarQueryVo = new RentalEBike();
                rentalCarQueryVo.setCarCode(mqttMessageJson.getId());

                Result<List<RentalEBike>> result = iRentalEBikeAPI.listByQuery(rentalCarQueryVo);
                if (result != null && result.isSuccess() && result.getResult() != null) {
                    List<RentalEBike> list = result.getResult();
                    for (RentalEBike car : list) {
                        car.setControlJson(taitModbusControllerResponse.toString());

                        try {
                            Result<Boolean> updateResult = iRentalEBikeAPI.updateById(car);
                            if (updateResult == null) {
                                log.error("更新车辆控制信息失败，car: {},  response: null", car);
                            } else if (!updateResult.isSuccess()) {
                                log.error("更新车辆控制信息失败，car: {},  errorCode: {}, errorMessage: {}", car, updateResult.getCode(), updateResult.getMessage());
                            } else if (!updateResult.getResult()) { //  即使 success 为 true，也要检查 result 是否为 true
                                log.error("更新车辆控制信息失败，car: {},  更新操作未成功", car);
                            }
                        } catch (Exception e) {
                            log.error("更新车辆控制信息失败，car: {}", car, e);
                        }
                    }
                } else {
                    if (result == null) {
                        log.error("查询车辆信息失败，response: null");
                    } else {
                        log.error("查询车辆信息失败，errorCode: {}, errorMessage: {}", result.getCode(), result.getMessage());
                    }
                }
            }
        } else {
            // 处理其他从机地址或错误情况
            System.err.println("未知的从机地址: " + slaveAddressTrans);
        }


    }

    private float roundToTwoDecimalPlaces(float value) {
        return BigDecimal.valueOf(value).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    public void calculateAverageMileagePerUnitPowerConsumption(TaiPower taiPower) {
        String deviceId = taiPower.getDeviceId();
        TaiPower lastPower = powerService.queryLastByDeviceId(deviceId);
        Location lastlocation = locationService.queryByDeviceId(deviceId);
        if (taiPower != null) {
            taiPower.setFpower(lastPower.getFpower());
        }

    }

    private void updateEPower(TaiPower taiPower, TaiPower power, Location location, TaitModbusPowerResponse tai) {
        //FieldStatus fieldStatus = new FieldStatus(location.getStatusField());

        String deviceId = taiPower.getDeviceId();
        Float x = power.getRPow() - taiPower.getRPow();
        System.out.println("消耗的电量" + x);
        // 如果 RPow 为 0，则将 EPower 设为 0
        if (power.getRPow() == 0) {
            taiPower.setEPower(0f);
        } else {
            // 如果电流为负且功率差为正，更新 EPower
            if (taiPower.getCurrent() < 0 && x > 0) {
                taiPower.setEPower(
                        power.getEPower() == null ? 0f : power.getEPower()
                );
                taiPower.setEPower(taiPower.getEPower() + x);
            } else {
                // 否则直接继承 power 的 EPower
                taiPower.setEPower(power.getEPower());
            }
        }
        if (location == null) {
            return;
        }

        if (x > 0 && taiPower.getCurrent() < 0 && power.getCurrent() < 0 && location.getSnnNumber() > 3) {
            float fPower = (power.getFpower() == null ? 0f : power.getFpower()) + x;
            taiPower.setFpower(fPower);
        } else {
            if (taiPower.getFpower() != null && power.getFpower() != null) {
                taiPower.setFpower(power.getFpower());
            } else {
                taiPower.setFpower(0f);
            }

        }
        System.out.println(taiPower.getFpower() + "单次统计消耗电量");
        if (taiPower.getFpower() > 10 && taiPower.getCurrent() < 0 && power.getCurrent() < 0) {
            Consumption lastConsumption = consumptionService.queryLatestByDeviceId(deviceId);
            // 创建新的能耗记录
            Consumption consumption = new Consumption();
            consumption.setDeviceId(deviceId);
            consumption.setTs(location.getTs());  // 使用当前 Location 的时间戳
            consumption.setFpower(taiPower.getFpower());  // 设置当前行驶里程
            consumption.setEpower(x);
            if (lastConsumption != null) {// 设置新消耗的电量
                Location prev500Location = locationService.queryNearestLocationBeforeTime(deviceId, lastConsumption.getTs());
                float energy500Mil = location.getMileage() - prev500Location.getMileage();
                // 如果存在上一次的能耗记录，则计算能耗差值
                if (energy500Mil > 0) {
                    consumption.setFMileage(energy500Mil);
                    float energy500Consumption = consumption.getFpower() / energy500Mil; // 计算 500 米的能耗
                    if (energy500Consumption == 0) {
                        consumption.setEConsum(lastConsumption.getEConsum());
                    } else {
                        consumption.setEConsum(energy500Consumption);
                    }
                }
            } else {
                RentalEBike rentalCarQueryVo = new RentalEBike();
                rentalCarQueryVo.setCarCode(deviceId);
                Result<List<RentalEBike>> result = iRentalEBikeAPI.listByQuery(rentalCarQueryVo);
                if (result != null && result.isSuccess() && result.getResult() != null) {
                    List<RentalEBike> existingCars = result.getResult();
                    if (existingCars.size() > 0) {
                        Cache cache = cacheManager.getCache(RentalCacheConstant.RENTAL_EBIKE_TYPE_CACHE);

                        Long carTypeId = existingCars.get(0).getCarTypeId();
                        if (carTypeId != null) {
                            RentalEBikeType carType = cache.get(carTypeId, RentalEBikeType.class);
//                            RentalEBikeType carType = iRentalEBikeAPI.selectCarTypeById(carTypeId);
                            if (carType != null && carType.getInitialConsumption() != null) {
                                consumption.setEConsum(carType.getInitialConsumption());
                            } else {
                                consumption.setEConsum(0f);
                            }

                        }
                    }

                }
            }
            // 添加新的能耗记录
            if (consumption.getEConsum() > 0.1f) {

                consumption.setEConsum(lastConsumption.getEConsum());
            }
            consumptionService.add(consumption);

            // 重置 `FPow`，因为超过 50 之后我们已经记录了消耗
            taiPower.setFpower(0f);

        }
    }


    public void handlePowerData(String deviceId, float batteryLevel) {
        // 从 Map 中获取该设备的低电量提醒信息
        LowBatteryAlertInfo alertInfo = lowBatteryAlertInfoMap.getOrDefault(deviceId, new LowBatteryAlertInfo());

        // 检查电量是否低于 15 且提醒次数小于 3 次
        if (batteryLevel < 15 && alertInfo.getAlertCount() < 3) {
            // 检查距离上次提醒是否已过一分钟
            long currentTime = System.currentTimeMillis();
            if (currentTime - alertInfo.getLastAlertTime() >= 60 * 1000) {
                // 发送低电量提醒
                sendLowBatteryAlert(deviceId, alertInfo.getAlertCount());

                // 更新提醒次数和上次提醒时间
                alertInfo.setAlertCount(alertInfo.getAlertCount() + 1);
                alertInfo.setLastAlertTime(currentTime);
                lowBatteryAlertInfoMap.put(deviceId, alertInfo);
            }
        } else if (batteryLevel >= 15) {
            // 如果电量恢复到 15 以上，重置提醒信息
            lowBatteryAlertInfoMap.put(deviceId, new LowBatteryAlertInfo());
        }

        // 其他处理电量数据的逻辑...
    }

    private void sendLowBatteryAlert(String deviceId, int alertCount) {
        // 这里添加发送提醒的代码，例如发送短信、推送通知等
        RentalEBike car = new RentalEBike();
        car.setCarCode(deviceId);
        carService.setPlayAudio(car, (byte) 2);
        System.out.println("设备 " + deviceId + " 电量低于 15%，请及时充电！ (提醒次数: " + (alertCount + 1) + ")");
    }

    // 低电量提醒信息类
    private static class LowBatteryAlertInfo {
        private int alertCount;
        private long lastAlertTime;

        public LowBatteryAlertInfo() {
            this.alertCount = 0;
            this.lastAlertTime = 0;
        }

        public int getAlertCount() {
            return alertCount;
        }

        public void setAlertCount(int alertCount) {
            this.alertCount = alertCount;
        }

        public long getLastAlertTime() {
            return lastAlertTime;
        }

        public void setLastAlertTime(long lastAlertTime) {
            this.lastAlertTime = lastAlertTime;
        }
    }

}
